using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UCL.Powersource.Analysis;

namespace UCL.Powersource.Helpers
{
    public static class DataTableBuilder
    {
        public static string FormatStringKey = "FormatString";

        public static Tuple<DataTable, DataTable> GetTableForActiveTeam(ITfsTeamProjectConfiguration activeTeam, IEnumerable<ITimeFrame> selectedTimeframes, IEnumerable<IStatistic> selectedStatistics, bool produceNormalizedTable = false)
        {
            //Create a new table and begin loading data
            var statTable = new DataTable();
            statTable.BeginLoadData();
            //Set the table name to the active stat's name
            statTable.TableName = activeTeam.UniqueName;

            //Prepare the timeframe column
            var dcTF = new DataColumn("TimeFrames", typeof(String)) { Caption = "Time Frame" };
            statTable.Columns.Add(dcTF);

            //Prepare the statistics columns
            foreach (var stat in selectedStatistics)
            {
                var dc = new DataColumn(stat.Name, typeof(double)) { AllowDBNull = true, Caption = stat.Label };
                dc.ExtendedProperties.Add(FormatStringKey, stat.FormatString);
                statTable.Columns.Add(dc);
            }


            //For every selected timeframe
            foreach (var timeframe in selectedTimeframes)
            {
                //Make a new row, enter that timeframe
                var teamRow = statTable.NewRow();
                teamRow[dcTF] = timeframe.Label;

                //and all results for that stat at that timeframe, for all selected statistics
                foreach (var stat in selectedStatistics)
                {
                    teamRow[stat.Name] = DBNull.Value;
                    StatisticTeamResult teamres;
                    var allTeamRes = stat.TeamResults.FirstOrDefault(a => a.Key == activeTeam);
                    if (allTeamRes.Key != null && allTeamRes.Value.TryGetValue(timeframe, out teamres))
                    {
                        if (teamres.Value != null && teamres.Value.HasValue)
                        {
                            teamRow[stat.Name] = teamres.Value.Value;
                        }
                    }
                    teamres = null;
                }
                statTable.Rows.Add(teamRow);
            }

            statTable.EndLoadData();

            var normalizedTable = new DataTable();

            if (produceNormalizedTable)
                normalizedTable = ProduceNormalizedTable(statTable);

            return new Tuple<DataTable,DataTable>(statTable, normalizedTable);
        }

        private static double Factor = 100;
        private static double MinValue = 0;

        private static DataTable ProduceNormalizedTable(DataTable statTable)
        {
            var normalizedTable = new DataTable();
            normalizedTable.BeginLoadData();
            normalizedTable.TableName = statTable.TableName;
            //Populate the normalized table columns
            foreach (DataColumn column in statTable.Columns)
            {
                var newColumn = new DataColumn(column.ColumnName, column.DataType) {AllowDBNull = column.AllowDBNull, Caption = column.Caption };
                normalizedTable.Columns.Add(newColumn);
            }

            //Create the normalized table rows
            for (int i = 0; i < statTable.Rows.Count; i++)
			{
                var newRow = normalizedTable.NewRow();
                normalizedTable.Rows.Add(newRow);
			}


            for (int i = 0; i < statTable.Columns.Count; i++)
            {
                List<double> valueSet = new List<double>(); 

                for (int j = 0; j < statTable.Rows.Count; j++)
                {
                    if (i == 0)
                    {
                        normalizedTable.Rows[j][0] = statTable.Rows[j][0];
                        continue;
                    }

                    normalizedTable.Rows[j][i] = statTable.Rows[j][i];
                    double? value = statTable.Rows[j][i] == DBNull.Value ? null : (double?)statTable.Rows[j][i];
                    if (value != null)
                        valueSet.Add((double)value);
                }

                if (valueSet.Count > 0)
                {
                    MinValue = valueSet.Min();

                    var ratio = Factor / (valueSet.Max() - MinValue);

                    for (int j = 0; j < normalizedTable.Rows.Count; j++)
                    {
                        if (normalizedTable.Rows[j][i] != DBNull.Value)
                        {
                            double normalizedResult = ((double)normalizedTable.Rows[j][i] - MinValue) * ratio;
                            normalizedTable.Rows[j][i] = normalizedResult;
                        }
                    }
                }
            }

            normalizedTable.EndLoadData();
            return normalizedTable;
        }

        public static Tuple<DataTable, DataTable> GetTableForActiveTimeFrame(ITimeFrame activeTimeframe, IEnumerable<ITfsTeamProjectConfiguration> selectedTeams, IEnumerable<IStatistic> selectedStatistics, bool produceNormalizedTable = false)
        {
            //Create a new table and begin loading data
            var statTable = new DataTable();
            statTable.BeginLoadData();

            //Set the table name to the active timeframe's name
            statTable.TableName = activeTimeframe.Label;

            //Prepare the stat column
            var dcT = new DataColumn("Teams", typeof(String)) { Caption = "Teams" };
            statTable.Columns.Add(dcT);

            //Prepare the statistics columns
            foreach (var stat in selectedStatistics)
            {
                var dc = new DataColumn(stat.Name, typeof(double)) { AllowDBNull = true, Caption = stat.Label };
                dc.ExtendedProperties.Add(FormatStringKey, stat.FormatString);
                statTable.Columns.Add(dc);
            }


            //For every selected stat
            foreach (var team in selectedTeams)
            {
                //Make a new row, enter that stat
                var teamRow = statTable.NewRow();
                teamRow[dcT] = team.UniqueName;

                //and all results for that stat at that timeframe, for all selected statistics
                foreach (var stat in selectedStatistics)
                {
                    teamRow[stat.Name] = DBNull.Value;
                    StatisticTeamResult teamres;
                    var allTeamRes = stat.TeamResults.FirstOrDefault(a => a.Key == team);
                    if (allTeamRes.Key != null && allTeamRes.Value.TryGetValue(activeTimeframe, out teamres))
                    {
                        if (teamres.Value != null && teamres.Value.HasValue)
                        {
                            teamRow[stat.Name] = teamres.Value.Value;
                        }
                    }
                    teamres = null;
                }
                statTable.Rows.Add(teamRow);
            }

            statTable.EndLoadData();

            var normalizedTable = new DataTable();

            if (produceNormalizedTable)
                normalizedTable = ProduceNormalizedTable(statTable);

            return new Tuple<DataTable, DataTable>(statTable, normalizedTable);
        }

        public static DataTable GetTableForActiveStatistic(IStatistic activeStatistic, IEnumerable<ITfsTeamProjectConfiguration> selectedTeams, IEnumerable<ITimeFrame> selectedTimeframes)
        {
            //Create a new table and begin loading data
            var statTable = new DataTable();
            statTable.BeginLoadData();

            //Set the table name to the active timeframe's name
            statTable.TableName = activeStatistic.Label;

            //Prepare the stat column
            var dcT = new DataColumn("Teams", typeof(String)) { Caption = "Teams" };
            statTable.Columns.Add(dcT);

            //Prepare the statistics columns
            foreach (var it in selectedTimeframes)
            {
                var dc = new DataColumn(it.Label, typeof(double)) { AllowDBNull = true, Caption = it.Label };
                dc.ExtendedProperties.Add(FormatStringKey, activeStatistic.FormatString);
                statTable.Columns.Add(dc);
            }


            //For every selected stat
            foreach (var team in selectedTeams)
            {
                //Make a new row, enter that stat
                var teamRow = statTable.NewRow();
                teamRow[dcT] = team.UniqueName;

                //and all results for that stat at that timeframe, for all selected statistics
                foreach (var it in selectedTimeframes)
                {
                    teamRow[it.Label] = DBNull.Value;
                    StatisticTeamResult teamres;
                    var allTeamRes = activeStatistic.TeamResults.FirstOrDefault(a => a.Key == team);
                    if (allTeamRes.Key != null && allTeamRes.Value.TryGetValue(it, out teamres))
                    {
                        if (teamres.Value != null && teamres.Value.HasValue)
                        {
                            teamRow[it.Label] = teamres.Value.Value;
                        }
                    }
                    teamres = null;
                }
                statTable.Rows.Add(teamRow);
            }

            statTable.EndLoadData();
            return statTable;
        }

        public static DataTable GetTableForTeamComparison(IEnumerable<ITfsTeamProjectConfiguration> selectedTeams, ITimeFrame activeTimeframe, IStatistic activeStatistic)
        {

            //Create a new table and begin loading data
            var statTable = new DataTable();
            if (!(activeStatistic is StatisticCompareTeamsBase)) return statTable;

            statTable.BeginLoadData();

            //Set the table name to the active statistics's and timeframe's name
            statTable.TableName = activeStatistic.Label + " at " + activeTimeframe.Label;

            //Prepare the team column
            var dcT = new DataColumn("Teams", typeof(String)) { Caption = "Teams" };
            statTable.Columns.Add(dcT);

            //Prepare the team columns
            foreach (var team in selectedTeams)
            {
                var dc = new DataColumn(team.UniqueName, typeof(double)) { AllowDBNull = true, Caption = team.Label };
                dc.ExtendedProperties.Add(FormatStringKey, activeStatistic.FormatString);
                statTable.Columns.Add(dc);
            }

            foreach (var team in selectedTeams)
            {
                //Make a new row, enter that team
                var teamRow = statTable.NewRow();
                teamRow[dcT] = team.UniqueName;

                foreach (var team2 in selectedTeams)
                {
                    if (team != team2)
                    {
                        teamRow[team2.UniqueName] = DBNull.Value;
                        StatisticCompareTeamsResultCollection teamres;
                        var allTeamRes = ((StatisticCompareTeamsBase)activeStatistic).CompareTeamResults.FirstOrDefault(a => a.Key == team);
                        if (allTeamRes.Key != null && allTeamRes.Value.TryGetValue(activeTimeframe, out teamres))
                        {
                            var innerRes = teamres.FirstOrDefault(a => a.TeamProject == team2);
                            if (innerRes != null) teamRow[team2.UniqueName] = innerRes.Value;
                        }
                        teamres = null;
                    }                    
                }
                statTable.Rows.Add(teamRow);
            }

            statTable.EndLoadData();
            return statTable;
        }
    }
}
